functor DeadDec (S : DEADDEC_STRUCTS) : DEADDEC =
struct
  open S
  
  
  structure Cfg = Cfg
  
  local open Cfg
  in structure Id = Id
     structure Intl = Intl
     structure T = Types
     structure B = Binop
     structure O = Operand
     structure K = Block
     structure S = Structs
     structure J = Transfer
     structure M = Stm
     structure F = Function
     structure P = Program
  end
  
  val tag = !Control.doShowOptVerbose
  fun debugPrint s =
      if tag
      then print s
      else ()
     
  val {get = appeared, set = setAppeared, destroy = destroyAppeared, ...} =
      Property.destGetSet (Id.plist, Property.initConst false)
  
  
  fun shrinkStm s =
      let val uses = M.uses s
          val def = case M.cookDest s
                     of NONE => ()
                      | SOME x => setAppeared (x, true)
      in  List.app (fn x => setAppeared (x, true)) uses
      end
      
  fun shrinkTransfer t =
      let val uses = J.uses t
      in  List.app (fn x => setAppeared (x, true)) uses
      end
      
  fun shrinkBlock b =
      case b
       of K.T {name,
               prop,
               stms,
               transfer,
               successors} =>
          let val _ = List.app shrinkStm stms
              val _ = shrinkTransfer transfer
          in  ()
          end
           
  fun shrinkBlocks bs = List.app shrinkBlock bs
  
  fun shrinkLocal {id, ty} =
      if appeared id
      then SOME {id = id, ty = ty}
      else NONE
      
  fun shrinkFunc f =
      case f
       of F.T {name,
               exit,
                rettype,
                args,
                locals,
                blocks,
                pre,
                post} =>
          let val _ = shrinkBlocks blocks
              fun doit l = 
                  case l
                   of [] => []
                    | x :: xs =>
                      (case shrinkLocal x
                        of NONE => doit xs
                         | SOME y => y :: doit xs)
              val newLocals = doit locals
              val new = F.T {name = name,
                             exit = exit,
                             rettype = rettype,
                             args = args,
                             locals = newLocals,
                             blocks = blocks,
                             pre = pre,
                             post = post}
              val _ = destroyAppeared ()
              val _ = debugPrint "\noutput the graph after deadDec\n"
              val _ = if tag
                      then F.toDot (new, "afterDeadDec")
                      else ()
          in  new
          end
  
  fun shrinkProg f =
      case f
       of P.T {structs, gvars, funcs, ...} =>
          let val _ = ()
          in  P.T {structs = structs,
                   gvars = gvars,
                   funcs = List.map shrinkFunc funcs}
          end
  
  fun shrink f=
      let val _ = debugPrint "\ndead declaration elemination starting\n"
          val _ = if tag
                  then File.output ("beforeDeadDec.c", P.toString f)
                  else ()
          val new = shrinkProg f
          val _ = if tag
                  then File.output ("afterDeadDec.c", P.toString new)
                  else ()
          val _ = debugPrint "\ndead declaration elemination finished\n"
      in  new
      end
end
